
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/cdev.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#include "char_dev.h"

MODULE_AUTHOR("liup");
MODULE_LICENSE("GPL v2");

/********************参数定义********************/
#if (REGISTER_CHRDEV_NEW_METHOD)
static dev_t xxx_devnum = 0;
#endif
static struct cdev *xxx_cdev_p = NULL;
static const struct file_operations xxx_fops = {
	.owner = THIS_MODULE,
	.llseek = xxx_llseek,
	.read = xxx_read,
	.write = xxx_write,
	//.unlocked_ioctl = xxx_ioctl,
	.open = xxx_open,
	.release = xxx_release,
};

unsigned char charDevTestFIFO[CHAR_DEV_TEST_FIFO_LENGTH];
unsigned char *pFIFO = charDevTestFIFO;

/********************函数定义********************/

static int xxx_open(struct inode *inode, struct file *filp)
{
	filp->private_data = pFIFO;
	return 0;
}

static int xxx_release(struct inode *inode, struct file *filp)
{
	return 0;
}

static ssize_t xxx_read(struct file *filp, char __user * buf, size_t size, loff_t * ppos)
{
	unsigned int count = size;
	struct cdev *dev = filp->private_data;
	unsigned long p = *ppos;
	if(copy_to_user(buf,dev + p,count))
	{
	   printk(KERN_INFO "read error\n");
	   return -EFAULT;
	}
	printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
	
	return count;
}

static ssize_t xxx_write(struct file *filp, const char __user * buf, size_t size, loff_t * ppos)
{
	unsigned long p = *ppos;
	unsigned int count = size;
	int ret = 0;
	struct cdev *dev = filp->private_data;

	if (p >= CHAR_DEV_TEST_FIFO_LENGTH)
	{
		printk(KERN_INFO "wirte pos error\n");
		return 0;
	}
	if (count > CHAR_DEV_TEST_FIFO_LENGTH - p)
		count = CHAR_DEV_TEST_FIFO_LENGTH - p;

	if (copy_from_user(dev + p, buf, count))
	{
		printk(KERN_INFO "wirte error\n");
		ret = -EFAULT;
	}
	else
	{
		*ppos += count;
		ret = count;

		printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);
	}

	return ret;
}

static loff_t xxx_llseek(struct file *filp, loff_t offset, int orig)
{
	loff_t ret = 0;
#if 0	
	switch (orig) {
	case 0:
		if (offset < 0) {
			ret = -EINVAL;
			break;
		}
		if ((unsigned int)offset > GLOBALMEM_SIZE) {
			ret = -EINVAL;
			break;
		}
		filp->f_pos = (unsigned int)offset;
		ret = filp->f_pos;
		break;
	case 1:
		if ((filp->f_pos + offset) > GLOBALMEM_SIZE) {
			ret = -EINVAL;
			break;
		}
		if ((filp->f_pos + offset) < 0) {
			ret = -EINVAL;
			break;
		}
		filp->f_pos += offset;
		ret = filp->f_pos;
		break;
	default:
		ret = -EINVAL;
		break;
	}
#endif
	return ret;
}

/*******************************************************************************
* 模块加载函数：完成模块初始化工作，执行加载内核模块命令时，自动执行。
* __init标识：直接编译进内核时，放在.init.text区
* 
*******************************************************************************/
static int __init xxx_module_init(void)
{
	int ret;
	
	printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n", current->comm, current->pid, __FILE__, __func__, __LINE__);
	/*注册字符设备*/
#if (REGISTER_CHRDEV_NEW_METHOD)
	/*方法1：已定义主设备号*/
	if(XXX_MAJOR)
	{
		xxx_devnum = MKDEV(XXX_MAJOR,XXX_MINOR_BASE);
		ret = register_chrdev_region(xxx_devnum, XXX_MINOR_DEVICE_NUM, XXX_DEV_NAME);
		//ret = register_chrdev(XXX_MAJOR, XXX_DEV_NAME, &xxx_fops); /*申请全部次设备号，并调用cdev_init和cdev_add*/
	}
	/*方法2：未定义主设备号*/
	else
	{
		ret = alloc_chrdev_region(&xxx_devnum, XXX_MINOR_BASE, XXX_MINOR_DEVICE_NUM, XXX_DEV_NAME);
	}
#else
	ret = register_chrdev(XXX_MAJOR, XXX_DEV_NAME, &xxx_fops);
#endif		
	if (ret < 0)
	{
		printk(KERN_NOTICE "Unable to register character device %s!\n",XXX_DEV_NAME);
		return ret;
	}
	
	/*申请设备结构体内存*/
#if 1	
	xxx_cdev_p = kmalloc(sizeof(struct cdev), GFP_KERNEL);
#else
	xxx_cdev_p = cdev_alloc();
#endif
	if (!xxx_cdev_p)
	{
		ret = -ENOMEM;
		goto fail;
	}
	memset(xxx_cdev_p, 0, sizeof(struct cdev));	
	
#if (REGISTER_CHRDEV_NEW_METHOD)	
	/*初始化设备结构体及关联文件操作方法*/
	cdev_init(xxx_cdev_p, &xxx_fops);
	xxx_cdev_p->owner = THIS_MODULE;
	xxx_cdev_p->ops = &xxx_fops;
	ret = cdev_add (xxx_cdev_p, xxx_devnum, XXX_MINOR_DEVICE_NUM);
	if(ret)
	{
		printk(KERN_NOTICE "Error to adding device %s!\n",XXX_DEV_NAME);
		goto fail;
	}
#endif	
	
	printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n", current->comm, current->pid, __FILE__, __func__, __LINE__);
	
	/*特定驱动的代码*/
	//pFIFO = kzalloc(CHAR_DEV_TEST_FIFO_LENGTH, GFP_KERNEL); /*申请一个测试buffer*/
	
	return 0;
	
fail:
	printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n", current->comm, current->pid, __FILE__, __func__, __LINE__);
	//xxx_module_exit();
#if (REGISTER_CHRDEV_NEW_METHOD)
	if (xxx_cdev_p) 
	{
		cdev_del(xxx_cdev_p);
		kfree(xxx_cdev_p);
	}
	unregister_chrdev_region(xxx_devnum,XXX_MINOR_DEVICE_NUM);
#else
	if (xxx_cdev_p) 
	{
		kfree(xxx_cdev_p);
	}	
	unregister_chrdev(XXX_MAJOR,  XXX_DEV_NAME); 
#endif	
	
	return ret;
}
module_init(xxx_module_init);

static void __exit xxx_module_exit(void)
{
	printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n", current->comm, current->pid, __FILE__, __func__, __LINE__);
#if (REGISTER_CHRDEV_NEW_METHOD)
	if (xxx_cdev_p) 
	{
		cdev_del(xxx_cdev_p);
		kfree(xxx_cdev_p);
	}
	unregister_chrdev_region(xxx_devnum,XXX_MINOR_DEVICE_NUM);
#else
	if (xxx_cdev_p) 
	{
		kfree(xxx_cdev_p);
	}	
	unregister_chrdev(XXX_MAJOR,  XXX_DEV_NAME); 
#endif

	/*特定驱动的代码*/
	//kfree(pFIFO);

	printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n", current->comm, current->pid, __FILE__, __func__, __LINE__);
}
module_exit(xxx_module_exit);
